#include "servlet.h"
#include "log.h"
#include <fnmatch.h>

namespace johnsonli 
{
namespace http 
{
    FunctionServlet::FunctionServlet(callback cb)
        :Servlet("FunctionServlet")
        ,m_cb(cb) 
    {}

    int32_t FunctionServlet::handle(johnsonli::http::HttpRequest::ptr request
               , johnsonli::http::HttpResponse::ptr response
               , johnsonli::http::HttpSession::ptr session) 
    {
        //调用回调
        return m_cb(request, response, session);
    }

    ServletDispatch::ServletDispatch(const std::string& servername)
        :Servlet("ServletDispatch") 
        ,m_servername(servername)
    {
        m_default.reset(new NotFoundServlet(servername));
    }

    int32_t ServletDispatch::handle(johnsonli::http::HttpRequest::ptr request
               , johnsonli::http::HttpResponse::ptr response
               , johnsonli::http::HttpSession::ptr session) 
    {
        // 根据请求路径，找到对应的servlet
        auto slt = getMatchedServlet(request->getPath());
        if(slt) 
        {
            slt->handle(request, response, session);
        }
        return 0;
    }

    void ServletDispatch::addServlet(const std::string& uri, Servlet::ptr slt) 
    {
        RWMutexType::WriteLock lock(m_mutex);
        m_datas[uri] = slt;
    }

    void ServletDispatch::addServlet(const std::string& uri
                        ,FunctionServlet::callback cb) 
    {
        RWMutexType::WriteLock lock(m_mutex);
        m_datas[uri].reset(new FunctionServlet(cb));
    }

    void ServletDispatch::addGlobServlet(const std::string& uri
                                    ,Servlet::ptr slt) 
    {
        RWMutexType::WriteLock lock(m_mutex);

        //有就不添加
        for(auto it = m_globs.begin();
                it != m_globs.end(); ++it) 
            {
            if(it->first == uri) 
            {
                m_globs.erase(it);
                break;
            }
        }
        m_globs.push_back(std::make_pair(uri, slt));
    }

    void ServletDispatch::addGlobServlet(const std::string& uri
                                ,FunctionServlet::callback cb) 
    {
        return addGlobServlet(uri, std::make_shared<FunctionServlet>(cb));
    }


    void ServletDispatch::delServlet(const std::string& uri) 
    {
        RWMutexType::WriteLock lock(m_mutex);
        m_datas.erase(uri);
    }

    void ServletDispatch::delGlobServlet(const std::string& uri) 
    {
        RWMutexType::WriteLock lock(m_mutex);
        for(auto it = m_globs.begin();
                it != m_globs.end(); ++it) 
        {
            if(it->first == uri) 
            {
                m_globs.erase(it);
                break;
            }
        }
    }

    Servlet::ptr ServletDispatch::getServlet(const std::string& uri)
    {
        RWMutexType::ReadLock lock(m_mutex);
        auto it = m_datas.find(uri);
        return it == m_datas.end() ? nullptr : it->second;
    }

    Servlet::ptr ServletDispatch::getGlobServlet(const std::string& uri) {
        RWMutexType::ReadLock lock(m_mutex);
        for(auto it = m_globs.begin();
                it != m_globs.end(); ++it) 
        {
            if(it->first == uri) 
            {
                return it->second;
            }
        }
        return nullptr;
    }

    Servlet::ptr ServletDispatch::getMatchedServlet(const std::string& uri) {
        RWMutexType::ReadLock lock(m_mutex);

        //先找m_datas，优先级更高
        auto mit = m_datas.find(uri);
        if(mit != m_datas.end()) 
        {
            return mit->second;
        }

        //再找m_globs
        for(auto it = m_globs.begin();
                it != m_globs.end(); ++it) 
        {
            if(!fnmatch(it->first.c_str(), uri.c_str(), 0)) 
            {
                return it->second;
            }
        }
        return m_default;
    }

    NotFoundServlet::NotFoundServlet(const std::string& name)
        :Servlet("NotFoundServlet")
        ,m_name(name) {
        m_content = "<html><head><title>404 Not Found"
            "</title></head><body><center><h1>404 Not Found</h1></center>"
            "<hr><center>" + name + "</center></body></html>";

    }

    int32_t NotFoundServlet::handle(johnsonli::http::HttpRequest::ptr request
                    , johnsonli::http::HttpResponse::ptr response
                    , johnsonli::http::HttpSession::ptr session) {
        response->setStatus(johnsonli::http::HttpStatus::NOT_FOUND);
        response->setHeader("Server", m_name);
        response->setHeader("Content-Type", "text/html");
        response->setBody(m_content);
        return 0;
    }

    static johnsonli::Logger::ptr g_logger = LOG_NAME("syatem");

    ReSourseServlet::ReSourseServlet(const std::string& path)
        : Servlet("ReSourseServlet")
        , m_path(path)
    {}

    int32_t ReSourseServlet::handle(johnsonli::http::HttpRequest::ptr request
                    , johnsonli::http::HttpResponse::ptr response
                    , johnsonli::http::HttpSession::ptr session)
    {
        
        auto path = m_path + request->getPath();

        //LOG_INFO(g_logger) << "handle path" << path;
        if(path.find("..") != std::string::npos)
        {
            response->setBody("invalid path");
            response->setStatus(johnsonli::http::HttpStatus::NOT_FOUND);
            return 0;
        }

        std::ifstream ifs(path);
        if(!ifs)
        {
            response->setBody("invalid file");
            response->setStatus(johnsonli::http::HttpStatus::NOT_FOUND);
            return 0;
        }

         std::stringstream ss;
         std::string line;

         while(std::getline(ifs, line))
         {
            ss << line << std::endl;
         }

        
        response->setBody(ss.str());
        response->setHeader("content-type", "text/html;charset=utf-8");
        
        return 0;
    }


}
}